package cz.gelion.shylock.invoice.web

import org.apache.wicket.protocol.http.WebApplication
import org.apache.wicket.Page
import org.apache.wicket.markup.html.WebPage
import cz.gelion.shylock.invoice.web.list.InvoiceListPage
import scala.util.DynamicVariable
import javax.persistence.EntityManager
import org.apache.wicket.request.cycle.IRequestCycleListener
import org.apache.wicket.request.cycle.AbstractRequestCycleListener
import org.apache.wicket.request.cycle.RequestCycle
import org.apache.wicket.request.IRequestHandler
import javax.persistence.Persistence
import cz.gelion.shylock.invoice.web.subj.SubjectListPage
import cz.gelion.shylock.invoice.Log
import org.apache.wicket.serialize.ISerializer
import org.apache.wicket.core.util.objects.checker
import org.apache.wicket.serialize.java.JavaSerializer
import org.apache.wicket.core.util.objects.checker.CheckingObjectOutputStream
import java.io.OutputStream
import java.io.ObjectOutputStream
import org.apache.wicket.core.util.objects.checker.NotDetachedModelChecker
import org.apache.wicket.core.util.io.SerializableChecker
import org.apache.wicket.core.util.objects.checker.IObjectChecker
import java.util.List
import java.util.ArrayList
import javax.persistence.Entity
import org.apache.wicket.request.Request
import org.apache.wicket.request.Response
import org.apache.wicket.protocol.http.WebSession
import org.apache.wicket.Session
import cz.gelion.shylock.invoice.entity.Manager
import org.apache.wicket.MetaDataKey
import cz.gelion.shylock.invoice.CurrentEnv

class Application extends WebApplication with Log {

  
  
  val emf = Persistence.createEntityManagerFactory("shylock")
  
  val requestListener =  new AbstractRequestCycleListener {
    
    
    override def onBeginRequest(c:RequestCycle) = {
      log.trace("begin request..." + c)
      CurrentEnv._manager.value = Application.user
      
    }
    override def onEndRequest(c:RequestCycle) = {
      log.trace("...end request " + c)
      Application.closeEm
    }
    override def onException(c:RequestCycle, e:Exception):IRequestHandler = {
      log.error("exception resolved", e)
      val em = Application.emCont.value
      if (em  != null) {
        if (em.getTransaction().isActive()) em.getTransaction().rollback()
        Application.closeEm
        
      }
      super.onException(c, e)
    }
    
    
    
    
  }
  
  override def init = {
    log.info("Initializing application...");
    getRequestCycleListeners().add(requestListener)
    
    getFrameworkSettings().setSerializer(new JavaSerializer(getApplicationKey()) {
   
    	override def newObjectOutputStream(out:OutputStream): ObjectOutputStream = { 
       		new CheckingObjectOutputStream(out, new NotDetachedModelChecker, new SerializableChecker.ObjectSerializationChecker, new IObjectChecker {
    			override def check(obj:Any):IObjectChecker.Result = {  
    				if (obj.getClass.getAnnotation(classOf[Entity]) != null) {
    					return new IObjectChecker.Result(IObjectChecker.Result.Status.FAILURE, "Object %s is entity managed".format(obj))
    				}
   					IObjectChecker.Result.SUCCESS
    			}
    			
    			override def getExclusions:List[Class[_]] = {
    				new ArrayList[Class[_]] 
    			}
    		}) 
    	}
    })    
  }
  
 
  override def getHomePage:Class[_ <: WebPage] = classOf[SubjectListPage]
  
  override def newSession(request:Request, response:Response):WebSession  = {
    log.trace("creating new session")
    val s = new WebSession(request)
    //TODO vytahnout z http requestu, ...
    s.setMetaData(Application.MANAGER, Application.em.find(classOf[Manager], "pepa"))
    s
  }
  
}

object Application extends  Log {
  
	val MANAGER = new MetaDataKey[Manager]{}
	
	val emCont = new  DynamicVariable[EntityManager](null)
  
	def em:EntityManager = {
	  log.trace("entityManager = " + emCont.value)
	  if (emCont.value == null) {
	    log.trace("creating entityManager")
	    emCont.value = Persistence.createEntityManagerFactory("shylock").createEntityManager()
	  }
	  emCont.value
	}
	
	def closeEm = {
	  if (emCont.value != null  && emCont.value.isOpen()) {
	    log.trace("closing entityManager")
	    emCont.value.close()
	    emCont.value = null
	    
	  }
	}
	
	def user():Manager = Session.get.getMetaData(MANAGER)
	
}